package com.autumn.platform.dao;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.ibatis.session.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.w3c.dom.Node;

import com.autumn.platform.core.Utils;
import com.autumn.platform.dao.binding.handler.IMapperHandler;
import com.autumn.platform.dao.binding.handler.IParamResolverFactory;
import com.autumn.platform.dao.binding.handler.impl.DefaultParamResolverFactory;
import com.autumn.platform.dao.expression.IExpressionHandler;
import com.autumn.platform.dao.expression.impl.SpELExpressionHandler;
import com.autumn.platform.dao.schema.function.ISqlConfigFunction;
import com.autumn.platform.dao.schema.function.ISqlConfigFunctionFactory;
import com.autumn.platform.dao.schema.function.impl.BaseSqlConfigFunctionFactory;
import com.autumn.platform.dao.schema.script.IScriptHandler;
import com.autumn.platform.dao.schema.script.extend.DbScriptHandler;
import com.autumn.platform.dao.schema.script.original.BindScriptHandler;
import com.autumn.platform.dao.schema.script.original.ChooseScriptHandler;
import com.autumn.platform.dao.schema.script.original.ForEachScriptHandler;
import com.autumn.platform.dao.schema.script.original.IfScriptHandler;
import com.autumn.platform.dao.schema.script.original.OtherwiseScriptHandler;
import com.autumn.platform.dao.schema.script.original.SelectKeyScriptHandler;
import com.autumn.platform.dao.schema.script.original.SetScriptHandler;
import com.autumn.platform.dao.schema.script.original.TrimScriptHandler;
import com.autumn.platform.dao.schema.script.original.WhereScriptHandler;
import com.autumn.platform.dao.schema.statement.IStatementHandler;
import com.autumn.platform.dao.schema.statement.extend.DbStatementHandler;
import com.autumn.platform.dao.schema.statement.original.CRUDStatementHandler;
import com.autumn.platform.dao.schema.statement.original.CacheRefStatementHandler;
import com.autumn.platform.dao.schema.statement.original.CacheStatementHandler;
import com.autumn.platform.dao.schema.statement.original.ParameterMapStatementHandler;
import com.autumn.platform.dao.schema.statement.original.ResultMapStatementHandler;
import com.autumn.platform.dao.schema.statement.original.SqlStatementHandler;

public class HandlerRegistry {

    /**
     * 命名空间前缀
     */
    private static final String NAMESPACE = "http://com.autumn";

    /**
     * 原生配置翻译过来的默认命名空间
     */
    private static final String SQL_MAPPER_NAMESPACE = NAMESPACE + "/schema/sqlmapper";
    /**
     * 扩展元素所在的命名空间
     */
    private static final String SQL_MAPPER_DIALECT_NAMESPACE = NAMESPACE + "/schema/sqlmapper-dialect";
    /**
     * 默认表达式处理器
     */
    private static final IExpressionHandler DEFAULT_EXPRESSION_HANDLER = new SpELExpressionHandler();
    /**
     * 默认参数解析器工厂
     */
    private static final IParamResolverFactory DEFAULT_PARAM_RESOLVER_FACTORY = new DefaultParamResolverFactory();

    /**
     * 参数解析器工厂
     */
    private IParamResolverFactory paramResolverFactory = DEFAULT_PARAM_RESOLVER_FACTORY;

    /**
     * Mapper处理器
     */
    private final List<IMapperHandler> mapperHandlers = new LinkedList<IMapperHandler>();

    /**
     * 脚本级元素解析器
     */
    private final Map<String, Map<String, IScriptHandler>> scripts = new ConcurrentHashMap<String, Map<String, IScriptHandler>>();
    /**
     * 语句级元素解析器
     */
    private final Map<String, Map<String, IStatementHandler>> statements = new ConcurrentHashMap<String, Map<String, IStatementHandler>>();
    /**
     * 表达式处理器
     */
    private final List<IExpressionHandler> expressions = new LinkedList<IExpressionHandler>();
    /**
     * SQL配置函数
     */
    private final List<ISqlConfigFunction> sqlConfigFunctions = new LinkedList<ISqlConfigFunction>();

    public HandlerRegistry() {
        this.init();
    }

    protected void init() {
        //注册默认命名空间的StatementHandler
        register("cache-ref", new CacheRefStatementHandler());
        register("cache", new CacheStatementHandler());
        register("parameterMap", new ParameterMapStatementHandler());
        register("resultMap", new ResultMapStatementHandler());
        register("sql", new SqlStatementHandler());
        register("select|insert|update|delete", new CRUDStatementHandler());

        //注册默认命名空间的ScriptHandler
        register("trim", new TrimScriptHandler());
        register("where", new WhereScriptHandler());
        register("set", new SetScriptHandler());
        register("foreach", new ForEachScriptHandler());
        register("if|when", new IfScriptHandler());
        register("choose", new ChooseScriptHandler());
        //register("when", new IfScriptHandler());
        register("otherwise", new OtherwiseScriptHandler());
        register("bind", new BindScriptHandler());
        register("selectKey", new SelectKeyScriptHandler());

        // 注册自定义命名空间的处理器
        registerExtend("db", new DbStatementHandler(), new DbScriptHandler());
        registerSqlConfigFunctionFactory(new BaseSqlConfigFunctionFactory());
    }

    public IParamResolverFactory getParamResolverFactory() {
        return paramResolverFactory;
    }

    public void setParamResolverFactory(IParamResolverFactory iParamResolverFactory) {
        if (null != iParamResolverFactory) {
            this.paramResolverFactory = iParamResolverFactory;
        }
    }

    public void setMapperHandlers(List<IMapperHandler> mapperHandlers) {
        if (null != mapperHandlers && !mapperHandlers.isEmpty()) {
            this.mapperHandlers.addAll(mapperHandlers);
            Collections.sort(this.mapperHandlers, new Comparator<IMapperHandler>() {
                @Override
                public int compare(IMapperHandler o1, IMapperHandler o2) {
                    int i1 = o1.getOrder();
                    int i2 = o2.getOrder();
                    return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
                }
            });
        }
    }

    /**
     * 获取SQL配置函数
     * 
     * @param name
     * @return
     */
    public ISqlConfigFunction getSqlConfigFunction(String name, Configuration configuration) {
        for (ISqlConfigFunction sqlConfigFunction : sqlConfigFunctions) {
            if (sqlConfigFunction.supports(name, configuration)) {
                return sqlConfigFunction;
            }
        }
        return null;
    }

    public void registerSqlConfigFunction(ISqlConfigFunction... sqlConfigFunctions) {
        for (ISqlConfigFunction sqlConfigFunction : sqlConfigFunctions) {
            this.sqlConfigFunctions.add(sqlConfigFunction);
        }
    }

    public void registerSqlConfigFunctionFactory(ISqlConfigFunctionFactory... sqlConfigFunctionFactorys) {
        for (ISqlConfigFunctionFactory sqlConfigFunctionFactory : sqlConfigFunctionFactorys) {
            Collection<ISqlConfigFunction> sqlConfigFunctions = sqlConfigFunctionFactory.getSqlConfigFunctions();
            if (null != sqlConfigFunctions) {
                for (ISqlConfigFunction sqlConfigFunction : sqlConfigFunctions) {
                    this.sqlConfigFunctions.add(sqlConfigFunction);
                }
            }
        }
        AnnotationAwareOrderComparator.sort(sqlConfigFunctions);
    }

    /**
     * 同一个元素，同时处理脚本级和语句级解析器
     * 
     * @param namespaceUri
     * @param name
     * @param statement
     * @param script
     */
    public void registerStatementAndScriptHandler(String namespaceUri, String name, IStatementHandler statement, IScriptHandler script) {
        registerStatementHandler(namespaceUri, name, statement);
        registerScriptHandler(namespaceUri, name, script);
    }

    /**
     * 注册脚本级元素解析器，name支持竖线分隔多个元素名
     * 
     * @param namespaceUri
     * @param name
     * @param handler
     */
    public void registerStatementHandler(String namespaceUri, String name, IStatementHandler handler) {
        Map<String, IStatementHandler> hs = statements.get(namespaceUri);
        if (null == hs) {
            hs = new HashMap<String, IStatementHandler>();
            statements.put(namespaceUri, hs);
        }
        for (String n : name.split("\\s*\\|\\s*")) {
            hs.put(n, handler);
        }
    }

    /**
     * 获取节点的语句级解析器
     * 
     * @param node
     * @return
     */
    public IStatementHandler getStatementHandler(Node node) {
        String namespaceUri = node.getNamespaceURI();
        if (Utils.isBlank(namespaceUri)) {
            namespaceUri = SQL_MAPPER_NAMESPACE;
        }
        Map<String, IStatementHandler> hs = statements.get(namespaceUri);
        return null == hs ? null : hs.get(node.getLocalName());
    }

    /**
     * 注册语句级元素解析器，name支持竖线分隔多个元素名
     * 
     * @param namespaceUri
     * @param name
     * @param handler
     */
    public void registerScriptHandler(String namespaceUri, String name, IScriptHandler handler) {
        Map<String, IScriptHandler> hs = scripts.get(namespaceUri);
        if (null == hs) {
            hs = new HashMap<String, IScriptHandler>();
            scripts.put(namespaceUri, hs);
        }
        for (String n : name.split("\\s*\\|\\s*")) {
            hs.put(n, handler);
        }
    }

    /**
     * 获取节点的脚本级解析器
     * 
     * @param node
     * @return
     */
    public IScriptHandler getScriptHandler(Node node) {
        String namespaceUri = node.getNamespaceURI();
        if (Utils.isBlank(namespaceUri)) {
            namespaceUri = SQL_MAPPER_NAMESPACE;
        }
        Map<String, IScriptHandler> hs = scripts.get(namespaceUri);
        return null == hs ? null : hs.get(node.getLocalName());
    }

    /**
     * 注册表达式处理器
     * 
     * @param handler
     */
    public void registerExpressionHandler(IExpressionHandler handler) {
        expressions.add(handler);
    }

    /**
     * 注册一组表达式处理器
     * 
     * @param handlers
     */
    public void registerExpressionHandlers(Collection<? extends IExpressionHandler> handlers) {
        expressions.addAll(handlers);
    }

    /**
     * 获取表达式处理器
     * 
     * @param expression
     * @param configuration
     * @return
     */
    public IExpressionHandler getExpressionHandler(String expression, Configuration configuration) {
        for (IExpressionHandler handler : expressions) {
            if (handler.supports(expression, configuration)) {
                return handler;
            }
        }
        return DEFAULT_EXPRESSION_HANDLER;
    }

    /**
     * 获取Mapper处理器
     * 
     * @return
     */
    public List<IMapperHandler> getMapperHandlers() {
        return mapperHandlers;
    }

    private void registerExtend(String name, IStatementHandler statement, IScriptHandler script) {
        registerExtend(name, statement);
        registerExtend(name, script);
    }

    private void register(String name, IStatementHandler handler) {
        registerStatementHandler(SQL_MAPPER_NAMESPACE, name, handler);
    }

    private void registerExtend(String name, IStatementHandler handler) {
        registerStatementHandler(SQL_MAPPER_DIALECT_NAMESPACE, name, handler);
    }

    private void register(String name, IScriptHandler handler) {
        registerScriptHandler(SQL_MAPPER_NAMESPACE, name, handler);
    }

    private void registerExtend(String name, IScriptHandler handler) {
        registerScriptHandler(SQL_MAPPER_DIALECT_NAMESPACE, name, handler);
    }

}
